<?php
declare(strict_types=1);

namespace app\common\job;

use app\common\model\banxi\learn\LearnSkRecord;
use app\common\service\learn\LearnSkRecordService;
use app\common\service\queue\QueueService;
use think\facade\Log;
use think\queue\Job;

class EndSk
{
    public function fire(Job $job, array $data): void
    {
        logSave([
            'file' => __FILE__,
            'message' => 'endSk 任务开始',
            'data' => $data,
            'start_time' => date('Y-m-d H:i:s')
        ], 'endSK');

        $recordId = $data['recordId'] ?? 0;
        if ($recordId <= 0) {
            $this->handleInvalidRecord($job, $data, 'recordId为空');
            return;
        }

        try {
            $learnSkRecordModel = new LearnSkRecord();
            $recordInfo = $learnSkRecordModel->where('id', $recordId)->find();

            if (!$recordInfo) {
                $this->handleInvalidRecord($job, $data, '上课记录不存在');
                return;
            }

            if ($recordInfo->isEnd) {
                $this->handleInvalidRecord($job, $data, '课程已结束');
                return;
            }

            // 使用容器解析服务实例
            $learnSkService = app()->make(LearnSkRecordService::class);
            // 修复参数传递问题
            $result = $learnSkService->endSk($recordInfo['trainerId'], $recordInfo['appointmentId']);

            if ($result) {
                // 任务执行成功
                $this->handleSuccess($job, $data);
            } else {
                // 任务执行失败
                $this->handleFailure($job, $data);
            }
        } catch (\Exception $e) {
            $this->handleException($job, $data, $e);
        } catch (\Throwable $t) {
            $this->handleThrowable($job, $data, $t);
        }
    }

    /**
     * 处理无效记录情况
     */
    private function handleInvalidRecord(Job $job, array $data, string $reason): void
    {
        $job->delete();
        logSave([
            'file' => __FILE__,
            'message' => "endSk 队列任务失败，{$reason}",
            'data' => $data,
            'end_time' => date('Y-m-d H:i:s')
        ], 'endSK');
    }

    /**
     * 处理任务成功情况
     */
    private function handleSuccess(Job $job, array $data): void
    {
        // 添加单词发音任务
        $queueService = new QueueService();
        $queueService->addWordVocalJob();

        // 删除当前任务
        $job->delete();

        logSave([
            'file' => __FILE__,
            'message' => 'endSk 任务执行成功',
            'data' => $data,
            'end_time' => date('Y-m-d H:i:s')
        ], 'endSK');
    }

    /**
     * 处理任务失败情况
     */
    private function handleFailure(Job $job, array $data): void
    {
        $attempts = $job->attempts();

        if ($attempts > 3) {
            $job->delete();
            logSave([
                'file' => __FILE__,
                'message' => "队列任务失败超过3次，已删除",
                'data' => $data,
                'attempts' => $attempts,
                'end_time' => date('Y-m-d H:i:s')
            ], 'endSK');
        } else {
            logSave([
                'file' => __FILE__,
                'message' => "队列任务失败，将自动重试",
                'data' => $data,
                'attempts' => $attempts,
            ], 'endSK');
            // 任务会自动重新加入队列
        }
    }

    /**
     * 处理异常情况
     */
    private function handleException(Job $job, array $data, \Exception $e): void
    {
        $this->handleFailure($job, $data);
        logSave([
            'file' => __FILE__,
            'message' => "EndSk Exception",
            'data' => $data,
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString()
        ], 'endSK');
    }

    /**
     * 处理致命错误
     */
    private function handleThrowable(Job $job, array $data, \Throwable $t): void
    {
        $this->handleFailure($job, $data);
        logSave([
            'file' => __FILE__,
            'message' => "EndSk Throwable",
            'data' => $data,
            'error' => $t->getMessage(),
            'trace' => $t->getTraceAsString()
        ], 'endSK');
    }

    /**
     * 任务失败回调
     */
    public function failed(array $data): void
    {
        Log::error('队列任务最终失败', $data);
        logSave([
            'file' => __FILE__,
            'message' => '队列任务最终失败',
            'data' => $data,
            'end_time' => date('Y-m-d H:i:s')
        ], 'endSK');
    }
}
